package com.qqt.csr.im.service;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.qqt.csr.common.utils.SnowflakeUtil;
import com.qqt.csr.im.dto.MsgAccountDTO;
import com.qqt.csr.im.entity.Account;
import com.qqt.csr.im.entity.Room;
import com.qqt.csr.im.entity.RoomMember;
import com.qqt.csr.im.entity.Conversation;
import com.qqt.csr.im.enums.ConversationStateEnum;
import com.qqt.csr.im.mapper.RoomMapper;
import com.qqt.csr.im.vo.req.QueryingRoomListReqVO;
import com.qqt.csr.im.vo.resp.RoomRespVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * im房间
 */
@Slf4j
@Service
public class RoomService extends ServiceImpl<RoomMapper, Room> {
    @Autowired
    private AccountService accountService;
    @Autowired
    private RoomMemberService roomMemberService;

    /**
     * 创建或更新房间
     *
     * @param conversation
     * @param room
     */
    public void updateLastConversation(Conversation conversation, Room room) {
        room.setLastConversationId(conversation.getId());
        room.setLastConversationState(conversation.getState().getCode());
        room.setLastConversationDate(DateUtil.parse(conversation.getStartTime()));
        this.lambdaUpdate().set(Room::getLastConversationId, room.getLastConversationId())
                .set(Room::getLastConversationState, room.getLastConversationState())
                .set(Room::getLastConversationDate, room.getLastConversationDate())
                .set(Room::getExt, room.getExt())
                .set(Room::getUpdateTime, DateUtil.now())
                .eq(Room::getId, room.getId()).update();
    }

    /**
     * 创建或更新房间
     *
     * @param accountIdList
     * @param conversation
     * @param room
     */
    @Transactional(rollbackFor = Throwable.class)
    public void save(List<Long> accountIdList, Conversation conversation, Room room) {
        room.setId(room.getId() != null ? room.getId() : SnowflakeUtil.nextId());
        room.setName(StringUtils.EMPTY);
        room.setLastConversationId(conversation.getId());
        room.setLastConversationState(conversation.getState().getCode());
        room.setLastConversationDate(DateUtil.parse(conversation.getStartTime()));
        room.setDeleteFlag(0);
        this.save(room);
        roomMemberService.add(room, accountIdList);
    }

    /**
     * 获取聊天人所在的房间id
     *
     * @param accountIdList
     * @return
     */
    public Room queryRoomBy(List<Long> accountIdList) {
        if (CollectionUtils.isEmpty(accountIdList) || accountIdList.size() < 2) {
            return null;
        }
        Long roomId = roomMemberService.querySameRoomIdBy(accountIdList);
        if (roomId == null || roomId <= 0L) {
            return null;
        }
        Room room = this.lambdaQuery().select().eq(Room::getId, roomId).one();
        if (room == null) {
            return null;
        }
        List<RoomMember> roomMemberList = roomMemberService.queryMemberListBy(roomId);
        room.setRoomMemberList(roomMemberList);
        return room;
    }

    /**
     * 更新房间的会话状态
     *
     * @param conversationIdList
     */
    public void updateRoomCloseConversationState(List<String> conversationIdList) {
        if (CollectionUtils.isEmpty(conversationIdList)) {
            return;
        }
        this.lambdaUpdate()
                .set(Room::getLastConversationState, ConversationStateEnum.END.getCode())
                .in(Room::getLastConversationId, conversationIdList).update();

    }

    /**
     * 查询房间列表
     * @param accountId
     * @param stateEnum
     * @return
     */
    public List<Room> queryRoomList(Long accountId, ConversationStateEnum stateEnum) {
        QueryingRoomListReqVO queryingRoomListReqVO = QueryingRoomListReqVO.builder()
                .accountId(accountId).state(stateEnum.getCode())
                .build();
        return this.baseMapper.queryRoomListBy(queryingRoomListReqVO);
    }

    /**
     * 获取房间列表
     *
     * @param req
     * @return
     */
    public List<RoomRespVO> queryRoomVOList(QueryingRoomListReqVO req) {
        List<Room> roomList = this.baseMapper.queryRoomListBy(req);
        if(CollectionUtils.isEmpty(roomList)){
            return Lists.newArrayList();
        }

        List<Long> roomIdList = roomList.stream().map(Room::getId).distinct().collect(Collectors.toList());
        Map<Long, List<RoomMember>> roomMemberMap = new HashMap<>();
        Stopwatch stopwatch = Stopwatch.createStarted();
        if (ConversationStateEnum.NORMAL.getCode().equals(req.getState())) {
            roomMemberMap.putAll(roomMemberService.queryMemberMapFromCacheBy(roomIdList));
        } else {
            Lists.partition(roomIdList, 500).forEach(pList -> {
                roomMemberMap.putAll(roomMemberService.queryMemberMapFromDbBy(pList));
            });
        }
        stopwatch.stop();
        log.info("批量查询缓存耗时：{}ms", stopwatch.elapsed(TimeUnit.MILLISECONDS));

        List<Long> accountIdList = roomMemberMap.values().stream()
                .flatMap(Collection::stream)
                .map(RoomMember::getAccountId)
                .distinct().collect(Collectors.toList());
        Map<Long, Account> accountMap = accountService.getMapByIds(accountIdList);

        return roomList.stream()
                .map(room -> {
                    List<RoomMember> rmList = roomMemberMap.get(room.getId());
                    if (CollectionUtils.isEmpty(rmList)) {
                        return null;
                    }
                    List<Account> otherAccountList = rmList.stream()
                            .filter(rm->!rm.getAccountId().equals(req.getAccountId()))
                            .map(rm -> accountMap.get(rm.getAccountId()))
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());
                    if (CollectionUtils.isEmpty(otherAccountList)) {
                        return null;
                    }
                    return RoomRespVO.builder()
                            .id(room.getId().toString())
                            .member(MsgAccountDTO.of(accountMap.get(req.getAccountId())))
                            .otherMemberList(MsgAccountDTO.of(otherAccountList))
                            .lastConversationId(room.getLastConversationId())
                            .lastConversationState(room.getLastConversationState())
                            .lastConversationDate(room.getLastConversationDate())
                            .name(room.getName())
                            .roomExt(room.getExt())
                            .build();
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}
